/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "softbus_client_stub.h"

#include "discovery_service.h"
#include "ipc_skeleton.h"
#include "ipc_types.h"
#include "message_parcel.h"
#include "securec.h"
#include "softbus_def.h"
#include "softbus_errcode.h"
#include "softbus_interface.h"
#include "softbus_log.h"

extern "C" void __attribute__ ((weak)) DiscClientOnDeviceFound(const DeviceInfo *device)
{
    (void)device;
    LOG_INFO("client DiscOnDeviceFound Weak!\n");
}

extern "C" void __attribute__ ((weak)) DiscClientOnDiscoverySuccess(int32_t subscribeId)
{
    (void)subscribeId;
    LOG_INFO("client DiscOnDiscoverySuccess Weak!\n");
}

extern "C" void __attribute__ ((weak)) DiscClientOnDiscoverFailed(int32_t subscribeId, DiscoveryFailReason failReason)
{
    (void)subscribeId;
    (void)failReason;
    LOG_INFO("client DiscOnDiscoverFailed Weak!\n");
}

extern "C" void __attribute__ ((weak)) DiscClientOnPublishSuccess(int32_t publishId)
{
    (void)publishId;
    LOG_INFO("client DiscOnPublishSuccess Weak!\n");
}

extern "C" void __attribute__ ((weak)) DiscClientOnPublishFail(int32_t publishId, PublishFailReason reason)
{
    (void)publishId;
    (void)reason;
    LOG_INFO("client DiscOnPublishFail Weak!\n");
}

extern "C" int __attribute__ ((weak)) TransOnChannelOpened(const char *pkgName, const char *sessionName,
    const ChannelInfo *channel)
{
    LOG_INFO("client TransOnChannelOpened Weak!\n");
    return SOFTBUS_OK;
}

extern "C" int __attribute__ ((weak)) TransOnChannelOpenFailed(const char *pkgName, int32_t channelId)
{
    LOG_INFO("client TransOnChannelOpenFailed Weak!\n");
    return SOFTBUS_OK;
}

extern "C" int __attribute__ ((weak)) TransOnChannelClosed(const char *pkgName, int32_t channelId)
{
    LOG_INFO("client TransOnChannelClosed Weak!\n");
    return SOFTBUS_OK;
}

extern "C" int __attribute__ ((weak)) TransOnChannelMsgReceived(const char *pkgName, int32_t channelId,
    const void *data, uint32_t len, int32_t type)
{
    LOG_INFO("client TransOnChannelMsgReceived Weak!\n");
    return SOFTBUS_OK;
}

extern "C" int __attribute__ ((weak)) LnnOnJoinResult(void *addr, const char *networkId, int retCode);
extern "C" int __attribute__ ((weak)) LnnOnLeaveResult(const char *networkId, int retCode);
extern "C" int __attribute__ ((weak)) LnnOnNodeOnlineStateChanged(bool isOnline, void *info);
extern "C" int __attribute__ ((weak)) LnnOnNodeBasicInfoChanged(void *info, int32_t type);

namespace OHOS {
SoftBusClientStub::SoftBusClientStub()
{
    memberFuncMap_[CLIENT_DISCOVERY_DEVICE_FOUND] =
        &SoftBusClientStub::OnDeviceFoundInner;
    memberFuncMap_[CLIENT_DISCOVERY_SUCC] =
        &SoftBusClientStub::OnDiscoverySuccessInner;
    memberFuncMap_[CLIENT_DISCOVERY_FAIL] =
        &SoftBusClientStub::OnDiscoverFailedInner;
    memberFuncMap_[CLIENT_PUBLISH_SUCC] =
        &SoftBusClientStub::OnPublishSuccessInner;
    memberFuncMap_[CLIENT_PUBLISH_FAIL] =
        &SoftBusClientStub::OnPublishFailInner;
    memberFuncMap_[CLIENT_ON_CHANNEL_OPENED] =
        &SoftBusClientStub::OnChannelOpenedInner;
    memberFuncMap_[CLIENT_ON_CHANNEL_OPENFAILED] =
        &SoftBusClientStub::OnChannelOpenFailedInner;
    memberFuncMap_[CLIENT_ON_CHANNEL_CLOSED] =
        &SoftBusClientStub::OnChannelClosedInner;
    memberFuncMap_[CLIENT_ON_CHANNEL_MSGRECEIVED] =
        &SoftBusClientStub::OnChannelMsgReceivedInner;
    memberFuncMap_[CLIENT_ON_JOIN_RESULT] =
        &SoftBusClientStub::OnJoinLNNResultInner;
    memberFuncMap_[CLIENT_ON_LEAVE_RESULT] =
        &SoftBusClientStub::OnLeaveLNNResultInner;
    memberFuncMap_[CLIENT_ON_NODE_ONLINE_STATE_CHANGED] =
        &SoftBusClientStub::OnNodeOnlineStateChangedInner;
    memberFuncMap_[CLIENT_ON_NODE_BASIC_INFO_CHANGED] =
        &SoftBusClientStub::OnNodeBasicInfoChangedInner;
}

int32_t SoftBusClientStub::OnRemoteRequest(uint32_t code,
    MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    LOG_INFO("SoftBusClientStub::OnReceived, code = %u", code);
    auto itFunc = memberFuncMap_.find(code);
    if (itFunc != memberFuncMap_.end()) {
        auto memberFunc = itFunc->second;
        if (memberFunc != nullptr) {
            return (this->*memberFunc)(data, reply);
        }
    }
    LOG_INFO("SoftBusClientStub: default case, need check.");
    return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
}

int32_t SoftBusClientStub::OnDeviceFoundInner(MessageParcel &data, MessageParcel &reply)
{
    const unsigned char *info = data.ReadBuffer(sizeof(DeviceInfo));
    if (info == NULL) {
        return SOFTBUS_ERR;
    }
    DeviceInfo deviceInfo;
    if (memcpy_s(&deviceInfo, sizeof(DeviceInfo), info, sizeof(DeviceInfo)) != EOK) {
        return SOFTBUS_ERR;
    }
    OnDeviceFound(&deviceInfo);
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnDiscoverFailedInner(MessageParcel &data, MessageParcel &reply)
{
    int subscribeId = data.ReadInt32();
    int failReason = data.ReadInt32();
    OnDiscoverFailed(subscribeId, failReason);
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnDiscoverySuccessInner(MessageParcel &data, MessageParcel &reply)
{
    int subscribeId = data.ReadInt32();
    OnDiscoverySuccess(subscribeId);
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnPublishSuccessInner(MessageParcel &data, MessageParcel &reply)
{
    int publishId = data.ReadInt32();
    OnPublishSuccess(publishId);
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnPublishFailInner(MessageParcel &data, MessageParcel &reply)
{
    int publishId = data.ReadInt32();
    int failReason = data.ReadInt32();
    OnPublishFail(publishId, failReason);
    return SOFTBUS_OK;
}

void SoftBusClientStub::OnDeviceFound(const void *device)
{
    DiscClientOnDeviceFound((DeviceInfo *)device);
}

void SoftBusClientStub::OnDiscoverFailed(int subscribeId, int failReason)
{
    DiscClientOnDiscoverFailed(subscribeId, (DiscoveryFailReason)failReason);
}

void SoftBusClientStub::OnDiscoverySuccess(int subscribeId)
{
    DiscClientOnDiscoverySuccess(subscribeId);
}

void SoftBusClientStub::OnPublishSuccess(int publishId)
{
    DiscClientOnPublishSuccess(publishId);
}

void SoftBusClientStub::OnPublishFail(int publishId, int reason)
{
    DiscClientOnPublishFail(publishId, (PublishFailReason)reason);
}

int32_t SoftBusClientStub::OnChannelOpened(const char *pkgName, const char *sessionName, const void *info)
{
    return TransOnChannelOpened(pkgName, sessionName, (ChannelInfo *)info);
}

int32_t SoftBusClientStub::OnChannelOpenFailed(const char *pkgName, int32_t channelId)
{
    return TransOnChannelOpenFailed(pkgName, channelId);
}

int32_t SoftBusClientStub::OnChannelClosed(const char *pkgName, int32_t channelId)
{
    return TransOnChannelClosed(pkgName, channelId);
}

int32_t SoftBusClientStub::OnChannelMsgReceived(const char *pkgName, int32_t channelId, const void *data,
    uint32_t len, int32_t type)
{
    return TransOnChannelMsgReceived(pkgName, channelId, data, len, type);
}

int32_t SoftBusClientStub::OnChannelOpenedInner(MessageParcel &data, MessageParcel &reply)
{
    const char *pkgName = data.ReadCString();
    if (pkgName == nullptr) {
        LOG_ERR("OnChannelOpenedInner read pkgName failed!");
        return SOFTBUS_ERR;
    }
    const char *sessionName = data.ReadCString();
    if (sessionName == nullptr) {
        LOG_ERR("OnChannelOpenedInner read pkgName failed!");
        return SOFTBUS_ERR;
    }

    ChannelInfo channel = {0};
    if (!data.ReadInt32(channel.channelId)) {
        LOG_ERR("OnChannelOpenedInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    if (!data.ReadInt32(channel.channelType)) {
        LOG_ERR("OnChannelOpenedInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    channel.fd = data.ReadFileDescriptor();
    if (!data.ReadBool(channel.isServer)) {
        LOG_ERR("OnChannelOpenedInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    if (!data.ReadBool(channel.isEnabled)) {
        LOG_ERR("OnChannelOpenedInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    if (!data.ReadInt32(channel.peerUid)) {
        LOG_ERR("OnChannelOpenedInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    if (!data.ReadInt32(channel.peerPid)) {
        LOG_ERR("OnChannelOpenedInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    channel.groupId = (char *)data.ReadCString();
    if (channel.groupId == nullptr) {
        LOG_ERR("OnChannelOpenedInner read addr failed!");
        return SOFTBUS_ERR;
    }
    if (!data.ReadUint32(channel.keyLen)) {
        LOG_ERR("OnChannelOpenedInner len failed!");
        return SOFTBUS_ERR;
    }
    channel.sessionKey = (char *)data.ReadRawData(channel.keyLen);
    if (channel.sessionKey == nullptr) {
        LOG_ERR("OnChannelOpenedInner read addr failed!");
        return SOFTBUS_ERR;
    }
    channel.peerSessionName = (char *)data.ReadCString();
    if (channel.peerSessionName == nullptr) {
        LOG_ERR("OnChannelOpenedInner read addr failed!");
        return SOFTBUS_ERR;
    }
    channel.peerDeviceId = (char *)data.ReadCString();
    if (channel.peerDeviceId == nullptr) {
        LOG_ERR("OnChannelOpenedInner read addr failed!");
        return SOFTBUS_ERR;
    }

    int ret = OnChannelOpened(pkgName, sessionName, &channel);
    bool res = reply.WriteInt32(ret);
    if (!res) {
        LOG_ERR("OnChannelOpenedInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnChannelOpenFailedInner(MessageParcel &data, MessageParcel &reply)
{
    const char* pkgName = data.ReadCString();
    if (pkgName == nullptr) {
        LOG_ERR("OnChannelOpenedInner read pkgName failed!");
        return SOFTBUS_ERR;
    }

    int32_t channelId;
    if (!data.ReadInt32(channelId)) {
        LOG_ERR("OnChannelOpenFailedInner read channel id failed!");
        return SOFTBUS_ERR;
    }

    int ret = OnChannelOpenFailed(pkgName, channelId);
    bool res = reply.WriteInt32(ret);
    if (!res) {
        LOG_ERR("OnChannelOpenFailedInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnChannelClosedInner(MessageParcel &data, MessageParcel &reply)
{
    const char* pkgName = data.ReadCString();
    if (pkgName == nullptr) {
        LOG_ERR("OnChannelOpenedInner read pkgName failed!");
        return SOFTBUS_ERR;
    }

    int32_t channelId;
    if (!data.ReadInt32(channelId)) {
        LOG_ERR("OnChannelClosedInner read channel id failed!");
        return SOFTBUS_ERR;
    }

    int ret = OnChannelClosed(pkgName, channelId);
    bool res = reply.WriteInt32(ret);
    if (!res) {
        LOG_ERR("OnChannelClosedInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnChannelMsgReceivedInner(MessageParcel &data, MessageParcel &reply)
{
    const char* pkgName = data.ReadCString();
    if (pkgName == nullptr) {
        LOG_ERR("OnChannelMsgReceivedInner read pkgName failed!");
        return SOFTBUS_ERR;
    }

    int32_t channelId;
    if (!data.ReadInt32(channelId)) {
        LOG_ERR("OnChannelMsgReceivedInner read channel id failed!");
        return SOFTBUS_ERR;
    }
    uint32_t len;
    if (!data.ReadUint32(len)) {
        LOG_ERR("OnChannelMsgReceivedInner read data len failed!");
        return SOFTBUS_ERR;
    }
    char *dataInfo = (char *)data.ReadRawData(len);
    if (dataInfo == nullptr) {
        LOG_ERR("OnChannelOpenedInner read dataInfo failed!");
        return SOFTBUS_ERR;
    }
    int32_t type;
    if (!data.ReadInt32(type)) {
        LOG_ERR("OnChannelMsgReceivedInner read type failed!");
        return SOFTBUS_ERR;
    }
    int ret = OnChannelMsgReceived(pkgName, channelId, dataInfo, len, type);
    bool res = reply.WriteInt32(ret);
    if (!res) {
        LOG_ERR("OnChannelMsgReceivedInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnJoinLNNResultInner(MessageParcel &data, MessageParcel &reply)
{
    uint32_t addrTypeLen;
    if (!data.ReadUint32(addrTypeLen)) {
        LOG_ERR("OnJoinLNNResultInner read addr type length failed!");
        return SOFTBUS_ERR;
    }
    void *addr = (void *)data.ReadRawData(addrTypeLen);
    if (addr == nullptr) {
        LOG_ERR("OnJoinLNNResultInner read addr failed!");
        return SOFTBUS_ERR;
    }
    int32_t retCode;
    if (!data.ReadInt32(retCode)) {
        LOG_ERR("OnJoinLNNResultInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    const char *networkId = nullptr;
    if (retCode == 0) {
        networkId = data.ReadCString();
        if (networkId == nullptr) {
            LOG_ERR("OnJoinLNNResultInner read networkId failed!");
            return SOFTBUS_ERR;
        }
    }
    int32_t retReply = OnJoinLNNResult(addr, addrTypeLen, networkId, retCode);
    if (!reply.WriteInt32(retReply)) {
        LOG_ERR("OnJoinLNNResultInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnLeaveLNNResultInner(MessageParcel &data, MessageParcel &reply)
{
    const char *networkId = data.ReadCString();
    if (networkId == nullptr) {
        LOG_ERR("OnLeaveLNNResultInner read networkId failed!");
        return SOFTBUS_ERR;
    }
    int32_t retCode;
    if (!data.ReadInt32(retCode)) {
        LOG_ERR("OnLeaveLNNResultInner read retCode failed!");
        return SOFTBUS_ERR;
    }
    int32_t retReply = OnLeaveLNNResult(networkId, retCode);
    if (!reply.WriteInt32(retReply)) {
        LOG_ERR("OnLeaveLNNResultInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnNodeOnlineStateChangedInner(MessageParcel &data, MessageParcel &reply)
{
    bool isOnline = false;
    if (!data.ReadBool(isOnline)) {
        LOG_ERR("OnNodeOnlineStateChangedInner read online state failed!");
        return SOFTBUS_ERR;
    }
    uint32_t infoTypeLen;
    if (!data.ReadUint32(infoTypeLen)) {
        LOG_ERR("OnNodeOnlineStateChangedInner read info type length failed!");
        return SOFTBUS_ERR;
    }
    void *info = (void *)data.ReadRawData(infoTypeLen);
    if (info == nullptr) {
        LOG_ERR("OnNodeOnlineStateChangedInner read basic info failed!");
        return SOFTBUS_ERR;
    }
    int32_t retReply = OnNodeOnlineStateChanged(isOnline, info, infoTypeLen);
    if (!reply.WriteInt32(retReply)) {
        LOG_ERR("OnNodeOnlineStateChangedInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnNodeBasicInfoChangedInner(MessageParcel &data, MessageParcel &reply)
{
    int32_t type;
    if (!data.ReadInt32(type)) {
        LOG_ERR("OnNodeBasicInfoChangedInner read type failed!");
        return SOFTBUS_ERR;
    }
    LOG_ERR("OnNodeBasicInfoChangedInner type %d", type);
    uint32_t infoTypeLen;
    if (!data.ReadUint32(infoTypeLen)) {
        LOG_ERR("OnNodeBasicInfoChangedInner read info type length failed!");
        return SOFTBUS_ERR;
    }
    void *info = (void *)data.ReadRawData(infoTypeLen);
    if (info == nullptr) {
        LOG_ERR("OnNodeBasicInfoChangedInner read basic info failed!");
        return SOFTBUS_ERR;
    }
    int32_t retReply = OnNodeBasicInfoChanged(info, infoTypeLen, type);
    if (!reply.WriteInt32(retReply)) {
        LOG_ERR("OnNodeBasicInfoChangedInner write reply failed!");
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

int32_t SoftBusClientStub::OnJoinLNNResult(void *addr, uint32_t addrTypeLen, const char *networkId, int retCode)
{
    (void)addrTypeLen;
    return LnnOnJoinResult(addr, networkId, retCode);
}

int32_t SoftBusClientStub::OnLeaveLNNResult(const char *networkId, int retCode)
{
    return LnnOnLeaveResult(networkId, retCode);
}

int32_t SoftBusClientStub::OnNodeOnlineStateChanged(bool isOnline, void *info, uint32_t infoTypeLen)
{
    (void)infoTypeLen;
    return LnnOnNodeOnlineStateChanged(isOnline, info);
}

int32_t SoftBusClientStub::OnNodeBasicInfoChanged(void *info, uint32_t infoTypeLen, int32_t type)
{
    (void)infoTypeLen;
    return LnnOnNodeBasicInfoChanged(info, type);
}
} // namespace OHOS